package com.baosight.risk.common.bean;

import com.baosight.risk.common.utils.IDGenerator;
import com.baosight.risk.common.utils.ShiroUtils;
import com.baosight.risk.common.utils.StringUtils;
import com.baosight.risk.web.page.PageDomain;
import com.baosight.risk.web.page.TableSupport;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Bean 工具类
 *
 * @author duanyongqiang
 */
@Slf4j
public class BeanUtils {
    /**
     * Bean方法名中属性名开始的下标
     */
    private static final int BEAN_METHOD_PROP_INDEX = 3;

    /**
     * 匹配getter方法的正则表达式
     */
    private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");

    /**
     * 匹配setter方法的正则表达式
     */
    private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");

    /**
     * Bean属性复制工具方法。
     *
     * @param dest 目标对象(空的)
     * @param src  源对象（有数据的）
     */
    public static void copyBeanProp(Object dest, Object src) {
        List<Method> destSetters = getSetterMethods(dest);
        List<Method> srcGetters = getGetterMethods(src);
        try {
            for (Method setter : destSetters) {
                for (Method getter : srcGetters) {
                    if (isMethodPropEquals(setter.getName(), getter.getName())
                            && setter.getParameterTypes()[0].equals(getter.getReturnType())) {
                        setter.invoke(dest, getter.invoke(src));
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 获取对象的setter方法。
     *
     * @param obj 对象
     * @return 对象的setter方法列表
     */
    public static List<Method> getSetterMethods(Object obj) {
        // setter方法列表
        List<Method> setterMethods = new ArrayList<Method>();

        // 获取所有方法
        Method[] methods = obj.getClass().getMethods();

        // 查找setter方法

        for (Method method : methods) {
            Matcher m = SET_PATTERN.matcher(method.getName());
            if (m.matches() && (method.getParameterTypes().length == 1)) {
                setterMethods.add(method);
            }
        }
        // 返回setter方法列表
        return setterMethods;
    }

    /**
     * 获取对象的getter方法。
     *
     * @param obj 对象
     * @return 对象的getter方法列表
     */

    public static List<Method> getGetterMethods(Object obj) {
        // getter方法列表
        List<Method> getterMethods = new ArrayList<Method>();
        // 获取所有方法
        Method[] methods = obj.getClass().getMethods();
        // 查找getter方法
        for (Method method : methods) {
            Matcher m = GET_PATTERN.matcher(method.getName());
            if (m.matches() && (method.getParameterTypes().length == 0)) {
                getterMethods.add(method);
            }
        }
        // 返回getter方法列表
        return getterMethods;
    }

    /**
     * 检查Bean方法名中的属性名是否相等。<br>
     * 如getName()和setName()属性名一样，getName()和setAge()属性名不一样。
     *
     * @param m1 方法名1
     * @param m2 方法名2
     * @return 属性名一样返回true，否则返回false
     */

    public static boolean isMethodPropEquals(String m1, String m2) {
        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
    }


    /**
     * 初始化对象
     */
    public static Object initBean(Object o) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(o.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (key.equals("id")) {
                    Method setter = property.getWriteMethod();
                    setter.invoke(o, IDGenerator.getIdStr());
                } else if (key.equals("createTime") || key.equals("updateTime")) {
                    Method setter = property.getWriteMethod();
                    setter.invoke(o, new Date());
                } else if (key.equals("createBy") || key.equals("updateBy")) {
                    Method setter = property.getWriteMethod();
                    String loginName = "admin";
                    try {
                        loginName = ShiroUtils.getLoginName();
                    } catch (Exception e) {
                    }
                    setter.invoke(o, loginName);
                }
            }
        } catch (Exception e) {
            log.info("BeanUtils.initBean Error " + e.getMessage());
        }
        return o;
    }

    /**
     *  初始化扩展字段
     */
    public static Object initExt(Object o) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(o.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (key.matches("ext\\d*")){
                    Method setter = property.getWriteMethod();
                    setter.invoke(o, "");
                }
            }
        } catch (Exception e) {
            log.info("BeanUtils.initExt Error " + e.getMessage());
        }
        return o;
    }

    /**
     * 配置更新日期以及更新人
     */
    public static Object updateBean(Object o) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(o.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if ("updateTime".equals(key)) {
                    Method setter = property.getWriteMethod();
                    setter.invoke(o, new Date());
                } else if ("updateBy".equals(key)) {
                    Method setter = property.getWriteMethod();
                    String loginName = "admin";
                    try {
                        loginName = ShiroUtils.getLoginName();
                    } catch (Exception e) {
                    }
                    setter.invoke(o, loginName);
                }
            }
        } catch (Exception e) {
            log.info("BeanUtils.updateBean Error " + e.getMessage());
        }
        return o;
    }

    /**
     * 默认排序，防止rowOrder为空时，上下移动失效
     */
    public static boolean sortList(List list){
        boolean hasEmpty = false;
        boolean repeated = false;
        Map<String, Integer> map = new HashMap<>();
        try {
            if (CollectionUtils.isNotEmpty(list)) {
                out: for (Object t : list) {
                    BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
                    for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
                        if ("rowOrder".equals(property.getName())){
                            Object value = property.getReadMethod().invoke(t);
                            if (StringUtils.isEmpty(String.valueOf(value))) {
                                hasEmpty = true;
                                break out;
                            } else {
                                String valueOf = String.valueOf(value);
                                if(map.containsKey(valueOf)) {
                                    repeated = true;
                                    break out;
                                } else {
                                    map.put(valueOf, 0);
                                }
                            }
                        }
                    }
                }
                if (hasEmpty || repeated) {
                    // 按照分页排序
                    PageDomain pageDomain = TableSupport.buildPageRequest();
                    Integer pageIndex = pageDomain.getPageIndex();
                    Integer pageSize = pageDomain.getPageSize();
                    if (StringUtils.isNotNull(pageIndex) && StringUtils.isNotNull(pageSize)) {
                        int index = ( ( pageIndex -1 ) * pageSize + 1 );
                        for (Object obj : list) {
                            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
                            for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
                                if ("rowOrder".equals(property.getName())){
                                    Method setter = property.getWriteMethod();
                                    setter.invoke(obj, index);
                                    index++;
                                    break;
                                }
                            }
                        }
                    } else {
                        // 按照列表排序
                        for (int i = 0; i < list.size(); i++) {
                            BeanInfo beanInfo = Introspector.getBeanInfo(list.get(i).getClass());
                            for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
                                if ("rowOrder".equals(property.getName())){
                                    Method setter = property.getWriteMethod();
                                    setter.invoke(list.get(i), (i+1));
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.info("BeanUtils.sortList Error " + e.getMessage());
        }
        return hasEmpty || repeated;
    }

    /**
     * 批量把entity转换成Map
     */
    public static List<Map<String, Object>> beanToMap(List entitys) {
        List<Map<String, Object>> list = new ArrayList<>();
        for (Object entity : entitys) {
            list.add(beanToMap(entity));
        }
        return list;
    }

    /**
     * 把entity转换成Map
     */
    public static Map<String, Object> beanToMap(Object entity){
        Map<String, Object> map = new HashMap<>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(entity.getClass());
            for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
                Method getter = property.getReadMethod();
                map.put(property.getName(), getter.invoke(entity));
            }
        } catch (Exception e) {
            log.info("BeanUtils.beanToMap Error " + e.getMessage());
        }
        return map;
    }

    /**
     * 批量把entity转换成Map，支持黑/白名单规则
     */
    public static List<Map<String, Object>> beanToMap(List entitys, List<String> blackProps, List<String> whiteProps) {
        List<Map<String, Object>> list = new ArrayList<>();
        for (Object entity : entitys) {
            list.add(beanToMap(entity, blackProps, whiteProps));
        }
        return list;
    }

    /**
     * 把entity转换成Map，支持黑/白名单规则
     */
    public static Map<String, Object> beanToMap(Object entity, List<String> blackProps, List<String> whiteProps){
        Map<String, Object> map = new HashMap<>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(entity.getClass());
            for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
                String type = "";
                boolean whiteFlag = false;
                boolean blackFlag = false;
                String propName = property.getName();
                if (CollectionUtils.isNotEmpty(whiteProps)) {
                    type += "W";
                    for (String whiteProp : whiteProps) {
                        if (propName.equals(whiteProp)) {
                            whiteFlag = true;
                            break;
                        }
                    }
                }
                if (CollectionUtils.isNotEmpty(blackProps)) {
                    type += "B";
                    for (String whiteProp : blackProps) {
                        if (propName.equals(blackProps)) {
                            blackFlag = true;
                            break;
                        }
                    }
                }
                switch (type) {
                    case "W":
                        if (whiteFlag) {
                            Method getter = property.getReadMethod();
                            map.put(property.getName(), getter.invoke(entity));
                        }
                        break;
                    case "B":
                        if (!blackFlag) {
                            Method getter = property.getReadMethod();
                            map.put(property.getName(), getter.invoke(entity));
                        }
                        break;
                    case "WB":
                        if (whiteFlag && !blackFlag) {
                            Method getter = property.getReadMethod();
                            map.put(property.getName(), getter.invoke(entity));
                        }
                        break;
                    default:
                        break;
                }
            }
        } catch (Exception e) {
            log.info("BeanUtils.beanToMap Error " + e.getMessage());
        }
        return map;
    }

    /**
     * 把map转换成entity
     */
    public static Object mapToBean(Map<String, Object> map, Object entity) {
        try {
            if (entity != null) {
                BeanInfo beanInfo = Introspector.getBeanInfo(entity.getClass());
                for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
                    Method setter = property.getWriteMethod();
                    setter.invoke(entity, map.get(property.getName()));
                }
                return entity;
            }
        } catch (Exception e) {
            log.info("BeanUtils.mapToBean Error " + e.getMessage());
        }
        return entity;
    }

    public static <T> T map2Object(Map<String, Object> map, Class<T> clazz) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        if (map == null) {
            return null;
        }
        T obj = null;
        try {
            // 使用newInstance来创建对象
            obj = clazz.newInstance();
            // 获取类中的所有字段
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                // 判断是拥有某个修饰符
                if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                    continue;
                }
                // 当字段使用private修饰时，需要加上
                field.setAccessible(true);
                // 获取参数类型名字
                String filedTypeName = field.getType().getName();
                // 判断是否为时间类型，使用equalsIgnoreCase比较字符串，不区分大小写
                // 给obj的属性赋值
                if (filedTypeName.equalsIgnoreCase("java.util.date")) {
                    String datetimestamp = (String) map.get(field.getName());
                    if (datetimestamp.equalsIgnoreCase("null")) {
                        field.set(obj, null);
                    } else {
                        field.set(obj, sdf.parse(datetimestamp));
                    }
                } else {
                    field.set(obj, map.get(field.getName()));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

}
